package ko;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import ko.util.KRect;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.LightingColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;

public class KEmitter extends KEntity {
	private Boolean active = true;
	//int frameWidth = 0, int frameHeight = 0
	public KEmitter(Bitmap source, int frameWidth, int frameHeight) {
		setSource(source, frameWidth, frameHeight);
		active = true;
	}
	/**
	 * Changes the source image to use for newly added particle types.
	 * @param	source			Source image.
	 * @param	frameWidth		Frame width.
	 * @param	frameHeight		Frame height.
	 */
	public void setSource(Bitmap source, int frameWidth, int frameHeight)
	{
		_source = source;
		if (_source == null) {
			Log.e("error", "Invalid source image.");
			return;
		}
		_width = _source.getWidth();
		_height = _source.getHeight();
		_frameWidth = (frameWidth != 0) ? frameWidth : _width;
		_frameHeight = (frameHeight != 0) ? frameHeight : _height;
		_frameCount = new Integer(_width / _frameWidth) * new Integer(_height / _frameHeight);
	}
	
	@Override 
	public void update() 
	{
		// quit if there are no particles
		if (_particle == null) return;
		
		// particle info
		float e = K.elapsed;
		KParticle p = _particle;
		KParticle n;
		
		// loop through the particles
		while (p != null)
		{
			// update time scale
			p._time += e;
			// remove on time-out
			if (p._time >= p._duration)
			{
				if (p._next != null) p._next._prev = p._prev;
				if (p._prev != null) p._prev._next = p._next;
				else _particle = p._next;
				n = p._next;
				p._next = _cache;
				p._prev = null;
				_cache = p;
				p = n;
				_particleCount--;
				continue;
			}
			
			// get next particle
			p = p._next;
		}
	}
	
	/** @private Renders the particles. */
	@Override
	public void render()
	{
		// quit if there are no particles//target:BitmapData, point:Point, camera:Point
		if (_particle == null) return;
		
		// get rendering position
		PointF _point = new PointF();
		_point.x = x;//point.x + 
		_point.y = y;//point.y + 
		
		// particle info
		float td;
		KParticle p = _particle;
		KParticleType type;
		KRect rect;
		
		// loop through the particles
		while (p != null)
		{
			// get time scale
			td = p._time / p._duration;
			
			// get particle type
			type = p._type;
			rect = type._frame;
			
			// get position
			_p.x = _point.x + p._x + p._moveX * td;
			_p.y = _point.y + p._y + p._moveY * td;
			
			// stops particles from moving when gravity is enabled
			// and if emitter.active = false (for game pausing for example)
			if (active)
			{
				p._moveY += p._gravity * td;
			}
			
			rect.x = rect.width() * type._frames.get((int)(td * type._frameCount));
			rect.y = (int)(rect.left / type._width) * rect.height();
			rect.x %= type._width;
			
			// draw particle
			Paint paint = new Paint();
			if (type._buffer != null)
			{
//				// get alpha
				_tint = (int) ((type._alpha + type._alphaRange * td) * 255f);
				paint.setAlpha(_tint);
//				// draw particle2
				//K.render.drawBitmap(type._source, _p.x , _p.y, paint);
				// draw particle2
				Matrix m = new Matrix();
				m.setTranslate(_p.x, _p.y);
				//m.postScale(K.SysRW, K.SysRH);
				K.render.drawBitmap(type._source, m, paint);
				//K.render.drawBitmap(type._source, _p.x, _p.y, paint);
			}
			else K.render.drawBitmap(type._source, _p.x, _p.y, null);
			
			// get next particle
			p = p._next;
		}
		
	}
	
	/**
	 * Creates a new KParticle type for this Emitter.
	 * @param	name		Name of the particle type.
	 * @param	frames		Array of frame indices for the particles to animate.
	 * frames: = null
	 * @return	A new KParticleType object.
	 */
	public KParticleType newType(String name, ArrayList<Integer> frames)
	{
		if (frames == null) {
			frames = new ArrayList<Integer>();
			frames.add(0);
		}
		if (_types.get(name) != null) {
			Log.e("_types", "Cannot add multiple particle types of the same name");
			return null;
		}
		return _types.put(name, new KParticleType(name, frames, _source, _frameWidth, _frameHeight));
	}
	
	/**
	 * Defines the motion range for a particle type.
	 * @param	name			The particle type.
	 * @param	angle			Launch Direction.
	 * @param	distance		Distance to travel.
	 * @param	duration		KParticle duration.
	 * @param	angleRange		Random amount to add to the particle's direction.
	 * @param	distanceRange	Random amount to add to the particle's distance.
	 * @param	durationRange	Random amount to add to the particle's duration.
	 * @param	ease			Optional easer function.
	 * angleRange:Number = 0, distanceRange:Number = 0, durationRange:Number = 0, ease:Function = null
	 * @return	This KParticleType object.
	 */
	public KParticleType setMotion(String name, float angle, float distance, float duration, float angleRange, float distanceRange, float durationRange)
	{
		return _types.get(name).setMotion(angle, distance, duration, angleRange, distanceRange, durationRange);
	}
	
	/**
	 * Sets the gravity range for a particle type.
	 * @param	name			The particle type.
	 * @param	gravity			Gravity amount to affect to the particle y velocity.
	 * @param	gravityRange	Random amount to add to the particle's gravity.
	 * gravity:Number = 0, gravityRange:Number = 0
	 * @return	This KParticleType object.
	 */
	public KParticleType setGravity(String name, float gravity, float gravityRange)
	{
		return _types.get(name).setGravity(gravity, gravityRange);
	}
	
	/**
	 * Sets the alpha range of the particle type.
	 * @param	name		The particle type.
	 * @param	start		The starting alpha.
	 * @param	finish		The finish alpha.
	 * @param	ease		Optional easer function.
	 * start:Number = 1, finish:Number = 0, ease:Function = null
	 * @return	This KParticleType object.
	 */
	public KParticleType setAlpha(String name, float start, float finish)
	{
		return _types.get(name).setAlpha(start, finish);
	}
	
	/**
	 * Sets the color range of the particle type.
	 * @param	name		The particle type.
	 * @param	start		The starting color.
	 * @param	finish		The finish color.
	 * @param	ease		Optional easer function.
	 * start:uint = 0xFFFFFF, finish:uint = 0, ease:Function = null
	 * @return	This KParticleType object.
	 */
//	public KParticleType setColor(String name, int start, int finish)
//	{
//		return _types.get(name).setColor(start, finish);
//	}
	
	/**
	 * Emits a particle.
	 * @param	name		KParticle type to emit.
	 * @param	x			X point to emit from.
	 * @param	y			Y point to emit from.
	 * @return
	 */
	public KParticle emit(String name, float x, float y)
	{
		KParticleType type = _types.get(name);
		if (type == null) {
			Log.e("_types.get", "KParticle type \"" + name + "\" does not exist.");
			return null;
		}
		KParticle p;
		
		if (_cache != null)
		{
			p = _cache;
			_cache = p._next;
		}
		else p = new KParticle();
		p._next = _particle;
		p._prev = null;
		if (p._next != null) p._next._prev = p;
		
		p._type = type;
		p._time = 0;
		p._duration = type._duration + type._durationRange * K.randomF();
		float a = type._angle + type._angleRange * K.randomF(),
			d = type._distance + type._distanceRange * K.randomF();
		p._moveX = (float) (Math.cos(a) * d);
		p._moveY = (float) (Math.sin(a) * d);
		p._x = x;
		p._y = y;
		p._gravity = type._gravity + type._gravityRange * K.randomF();
		_particleCount++;
		return (_particle = p);
	}
	
	/**
	 * Amount of currently existing particles.
	 */
	public int getParticleCount() { return _particleCount; }
	
	// KParticle information.
	//private Hashtable<String, List<KEntity>> _renderList;
	/** @private */ Hashtable<String, KParticleType> _types = new Hashtable<String, KParticleType>();
	/** @private */ private KParticle _particle;
	/** @private */ private KParticle _cache;
	/** @private */ private int _particleCount;
	
	// Source information.
	/** @private */ private Bitmap _source;
	/** @private */ private int _width;
	/** @private */ private int _height;
	/** @private */ private int _frameWidth;
	/** @private */ private int _frameHeight;
	/** @private */ private int _frameCount;
	
	// Drawing information.
	/** @private */ private PointF _p = new PointF();
	/** @private */ private int _tint;
//}

}
